/*
 * BitWriter.cpp
 *
 *  Created on: 22/10/2011
 *      Author: agustin
 */

#include "BitWriter.h"

BitWriter::BitWriter(const char* dest) {
	// Esta estructura se usa para determinar el tamaño optimo del buffer.
	struct stat s;
	stat(dest, &s);

	if (-1 == (fd = open(dest, O_WRONLY | O_CREAT))) {
		cout << dest << endl;
		perror("open() ");
		exit(1);
	}
	if (NULL
			== (buffer = (unsigned char*) malloc(
					s.st_blksize * sizeof(unsigned char)))) {
		if (NULL
				== (buffer = (unsigned char*) malloc(64 * sizeof(unsigned char)))) {
			close(fd);
			perror("malloc() ");
			exit(1);
		} else {
			this->buff_size = 64;
		}
	} else {
		this->buff_size = s.st_blksize;
	}

	this->buff_bit = 0;
	this->blocks_written = 0;

	//inicio el buffer completamente en 0
	for (int i = 0; i < this->buff_size; i++) {
		buffer[i] = buffer[i] & 0x0;
	}
}

bool BitWriter::bufferLleno() {
	return (this->buff_bit >= (this->buff_size * 8));
}

void BitWriter::escribirBit(unsigned char bit) {
	if (this->bufferLleno()) {
		//Escribo el buffer al archivo
		write(fd, buffer, this->buff_size);
		//Reinicio el buffer
		for (int i = 0; i < this->buff_size; i++) {
			buffer[i] = buffer[i] & 0x0;
		}
		this->buff_bit = 0;
		this->blocks_written++;
	}

	div_t divresult;
	divresult = div(this->buff_bit, 8);

	int byte_buff = divresult.quot;
	int offset_buff = divresult.rem;

	if (bit & 0x1) {
		//Pongo en 1 el bit correspondiente
		buffer[byte_buff] = (buffer[byte_buff] | (1 << offset_buff));
	}
	//No hago nada en caso contrario, porque el buffer ya esta en 0

	//incremento el numero del proximo bit a escribir del buffer;
	this->buff_bit++;
}

size_t BitWriter::getPosition() {
//devuelve la posicion em BITS
	return ((this->blocks_written * this->buff_size * 8) + this->buff_bit);
}

void BitWriter::cerrar() {

	//Grabo lo que me quedo en el buffer
	write(fd, buffer, this->buff_size);

	//Reinicio el buffer
	for (int i = 0; i < this->buff_size; i++) {
		buffer[i] = buffer[i] & 0x0;
	}
	this->buff_bit = 0;
	this->blocks_written = 0;

	close(fd);
}

BitWriter::~BitWriter() {
	//Grabo lo que me quedo en el buffer
	write(fd, buffer, this->buff_size);

	free(buffer);
	close(fd);
}

void BitWriter::abrir(char* dest) {
	// Esta estructura se usa para determinar el tamaño optimo del buffer.
	struct stat s;
	stat(dest, &s);

	if (-1 == (fd = open(dest, O_WRONLY | O_CREAT))) {
		cout << dest << endl;
		perror("open() ");
		exit(1);
	}
	if (NULL
			== (buffer = (unsigned char*) malloc(
					s.st_blksize * sizeof(unsigned char)))) {
		if (NULL
				== (buffer = (unsigned char*) malloc(64 * sizeof(unsigned char)))) {
			close(fd);
			perror("malloc() ");
			exit(1);
		} else {
			this->buff_size = 64;
		}
	} else {
		this->buff_size = s.st_blksize;
	}

	this->buff_bit = 0;
	this->blocks_written = 0;

	//inicio el buffer completamente en 0
	for (int i = 0; i < this->buff_size; i++) {
		buffer[i] = buffer[i] & 0x0;
	}
}
